import Singleton from "../net/Singleton";
import UIGuide from "../ui/UIGuide";
import LogUtil from "../utils/LogUtil";
import UIBase from "./UIBase";

/** UI缓存模式 */
export enum UICacheMode {
    /** 一次性的（立即销毁节点，预制体资源随即释放） */
    Once = 1,
    /** 正常的（立即销毁节点，但是缓存预制体资源） */
    Normal,
    /** 频繁的（只关闭节点，且缓存预制体资源） */
    Frequent
}

/** UI请求结果 */
export enum UIShowResult {
    /** 展示成功（已关闭） */
    Done = 1,
    /** 展示失败（加载失败） */
    Failed,
    /** 等待中（已加入等待队列） */
    Waiting
}

/** UI展示请求 */
export interface UIRequest {
    /** UI预制体相对路径 */
    path: string;
    /** UI参数 */
    options: any;
    /** 缓存模式 */
    mode?: number;
    /** UI组件 */
    ui?: UIBase;
    /** UI节点 */
    node?: cc.Node;
}

export class UIManager extends Singleton {
    /** 预制体缓存 */
    public get prefabCache() { return this._prefabCache; }
    private _prefabCache: Map<string, cc.Prefab> = new Map<string, cc.Prefab>();

    /** 节点缓存 */
    public get nodeCache() { return this._nodeCache; }
    private _nodeCache: Map<string, cc.Node> = new Map<string, cc.Node>();

    /** 当前UI请求 */
    public get current() { return this._current; }
    private _current: UIRequest = null;

     /** 引导UI */
     public get uiGuide() { return this._uiGuide; }
     private _uiGuide: UIGuide = null;

    /**
     * 获取UIRoot节点
     * @returns 
     */
    private _GetUIRoot() {
        return cc.find('Canvas/UIRoot');
    }

    /**
     * 动态加载开始回调
     * @param bgOpacity 背景透明度
     */
    public showUILoading(bgOpacity: number = 150,showUILoading:boolean=true) {
        let UILoading = cc.find('Canvas/UILoading');
        if (UILoading) {
            UILoading.active = showUILoading;
            let bg = UILoading.getChildByName('bg');
            bg && (bg.opacity = bgOpacity);
        }
    }

    /**
     * 动态加载结束回调
     */
    public hideUILoading() {
        let UILoading = cc.find('Canvas/UILoading');
        UILoading && (UILoading.active = false);
    }

    /**
     * 提示信息
    */
    public showMessage(msg:string) {
        this.show('prefabs/TipMessage',msg,UICacheMode.Once,false);
    }

    /**
     * 展示UI界面
     * @param path 预制体路径
     * @param options 参数
     * @param mode 缓存模式
     * @param showUILoading 展示加载动画
     * @returns 
     */
    public show<Options>(path: string, options?: Options, mode?: UICacheMode, showUILoading: boolean = true) {
        return new Promise(async res => {
            LogUtil.warn('[UIManager]', 'UI加载-->', path);
            // 保存为当前展示UI
            this._current = {
                path,
                options,
                mode
            };
            // 先在缓存中获取UI节点
            let node = this.getNodeFromCache(path);
            // 缓存中没有，动态加载预制体资源
            if (!cc.isValid(node)) {
                // 开始回调
                this.showUILoading && this.showUILoading(0,showUILoading);
                // 等待加载
                const prefab = await this.load(path);
                // 完成回调
                this.hideUILoading && this.hideUILoading();
                // 加载失败（一般是路径错误导致的）
                if (!cc.isValid(prefab)) {
                    cc.warn('[UIManager]', 'UI加载失败', path);
                    this._current = null;
                    res(UIShowResult.Failed);
                    return;
                }
                // 实例化节点
                node = cc.instantiate(prefab);
                // this._current = null;
            }
            // 获取继承自 UIBase 的UI组件
            const ui = node.getComponent(UIBase);
            if (!ui) {
                LogUtil.warn('[UIManager]', '未找到UI组件', path);
                this._current = null;
                res(UIShowResult.Failed);
                return;
            }
            // 添加到场景中
            if(path == 'prefabs/UILoading' || path == 'prefabs/UIGuide'){
                node.setParent(cc.Canvas.instance.node);
                if(path == 'prefabs/UIGuide') 
                    this._uiGuide = node.getComponent(UIGuide);
            }else{
                node.setParent(this._GetUIRoot() || cc.Canvas.instance.node);
            }
            // 显示在最上层
            node.setSiblingIndex(cc.macro.MAX_ZINDEX);
            // 设置完成回调
            const finishCallback = async (suspended: boolean) => {
                if (suspended) {
                    return;
                }
                // 回收
                this.recycle(path, node, mode);
                this._current = null;
                this._uiGuide = null;
                res(UIShowResult.Done);
            }
            ui.setFinishCallback(finishCallback);
            // 展示
            ui.show(options);
        });
    }

    /**
     * 从缓存中获取节点
     * @param path UI路径
     */
    private getNodeFromCache(path: string): cc.Node {
        // 从节点缓存中获取
        const nodeCache = this._nodeCache;
        if (nodeCache.has(path)) {
            const node = nodeCache.get(path);
            if (cc.isValid(node)) {
                return node;
            }
            // 删除无效引用
            nodeCache.delete(path);
        }
        // 从预制体缓存中获取
        const prefabCache = this._prefabCache;
        if (prefabCache.has(path)) {
            const prefab = prefabCache.get(path);
            if (cc.isValid(prefab)) {
                return cc.instantiate(prefab);
            }
            // 删除无效引用
            prefabCache.delete(path);
        }
        // 无
        return null;
    }

    /**
     * 回收UI
     * @param path UI路径
     * @param node UI节点
     * @param mode 缓存模式
     */
    private recycle(path: string, node: cc.Node, mode: UICacheMode = UICacheMode.Once) {
        switch (mode) {
            // 一次性
            case UICacheMode.Once:
                node.destroy();
                this._nodeCache.delete(path);
                this.release(path);
                break;
            // 正常
            case UICacheMode.Normal:
                node.destroy();
                this._nodeCache.delete(path);
                break;
            // 频繁
            case UICacheMode.Frequent:
                node.removeFromParent(false);
                this._nodeCache.set(path, node);
                break;
        }
    }

    /**
    * 加载并缓存UI预制体资源
    * @param path UI路径
    */
    public load(path: string): Promise<cc.Prefab> {
        return new Promise(res => {
            const prefabMap = this._prefabCache;
            // 先看下缓存里有没有，避免重复加载
            if (prefabMap.has(path)) {
                const prefab = prefabMap.get(path);
                // 缓存是否有效
                if (cc.isValid(prefab)) {
                    res(prefab);
                    return;
                } else {
                    // 删除无效引用
                    prefabMap.delete(path);
                }
            }
            // 动态加载
            cc.resources.load(path, (error: Error, prefab: cc.Prefab) => {
                if (error) {
                    res(null);
                    return;
                }
                // 缓存预制体
                prefabMap.set(path, prefab);
                // 增加引用计数
                prefab.addRef();
                res(prefab);
            });
        });
    }

    /**
     * 尝试释放UI资源（注意：UI内部动态加载的资源请自行释放）
     * @param path UI路径
     */
    public release(path: string) {
        // 移除节点
        const nodeCache = this._nodeCache;
        let node = nodeCache.get(path);
        if (node) {
            nodeCache.delete(path);
            if (cc.isValid(node)) {
                node.destroy();
            }
            node = null;
        }
        // 移除预制体
        const prefabCache = this._prefabCache;
        let prefab = prefabCache.get(path);
        if (prefab) {
            prefabCache.delete(path);
            prefab.decRef();
            prefab = null;
        }
    }
}